#pragma once
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include "Common.hpp"
#include "Log.hpp"
#include "inetAddr.hpp"
#include "ThreadPool.hpp"
#include "CommandExac.hpp"

using namespace LogModule;
using namespace ThreadPoolModule;
const uint16_t gport = 8080;
const int BACKLOG = 8;
class Server
{
    using task_t = std::function<void()>;
    // 传递一个字符串作为命令,并返回其执行结果
    using Handler_t = std::function<std::string(std::string)>;

private:
    struct ServerData
    {
        int sockfd;
        Server *server;
    };

public:
    Server(Handler_t handler, uint16_t port = gport)
        : _handler(handler), _port(port), _isrunning(false)
    {
    }
    void Init()
    {
        // 创建TCP套接字               //面向字节流
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            LOG(Loglevel::FATAL) << "socket filed";
            Die(SOCKET_ERROR);
        }
        LOG(Loglevel::INFO) << "socket success,sockfd:" << _listensockfd;
        // 地址复用
        int opt = 1;
        setsockopt(_listensockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
        // bind error的原因
        // 1.当一个 TCP 连接关闭时，会进入 TIME_WAIT 状态（持续约 2MSL，通常 1-4 分钟），此时端口仍被占用。
        // 如果服务器重启后尝试绑定同一个端口，会因端口被占用而失败。
        // 2.尝试绑定到已被其他进程使用的端口也会失败。
        //_REUSEADDR 允许在 TIME_WAIT 状态下重用本地地址，使得服务器可以快速重启并绑定端口。允许多个进程或线程绑定到同一个端口（需配合其他机制，如 fork）。
        //  SO_REUSEPORT允许多个套接字绑定到同一端口

        // 填充网络信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        // 云服务器不允许绑定IP,所以要填任意IP
        local.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_listensockfd, CONV(&local), sizeof(local));
        if (n < 0)
        {
            LOG(Loglevel::FATAL) << "bind filed";
            Die(BIND_ERROR);
        }
        LOG(Loglevel::INFO) << "bind success,sockfd:" << _listensockfd;
        // TCP是面向连接的,需要TCP随时随地等待被连接
        // 要将_listensockid设为监听状态
        n = listen(_listensockfd, BACKLOG); // 排队数,一般为4,8,16,32
        if (n < 0)
        {
            LOG(Loglevel::FATAL) << "listen filed";
            Die(LISTEN_ERROR);
        }
        LOG(Loglevel::INFO) << "listen success,sockfd:" << _listensockfd;
    }
    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // TCP不能直接进行通信,要先建立连接
            sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensockfd, CONV(&peer), &len);
            if (sockfd < 0)
            {
                LOG(Loglevel::ERROR) << "accept filed" << strerror(errno);
            }
            LOG(Loglevel::INFO) << "accept success,sockfd:" << sockfd;
            // V3 线程池版本 比较适合处理短任务，或者是用户量少的情况
            // task_t f = std::bind(&Server::HandlerRequest, this, sockfd); // 构建任务
            // ThreadPool<task_t>::getInstance()->Equeue(f);
            // 直接使用Lmaba表达式版本
            ThreadPool<task_t>::getInstance()->Equeue([this, sockfd]()
                                                      { this->HandlerRequest(sockfd); });
        }
    }
    void HandlerRequest(int sockfd)
    {
        LOG(Loglevel::INFO) << "HandlerRequest,sockfd:" << sockfd;
        char inbuffer[1024];
        while (true)
        {
            int n = recv(sockfd, inbuffer, sizeof(inbuffer) - 1, 0); // 收到客户端发来的指令
            if (n > 0)
            {
                inbuffer[n] = 0; // 确保inbuffer以null结尾
                std::string result = _handler(inbuffer);
                int m = send(sockfd, result.c_str(), result.size(), 0);
                (void)m;
            }
        }
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~Server()
    {
    }

private:
    int _listensockfd;
    uint16_t _port;
    bool _isrunning;
    // 远程命令执行
    Handler_t _handler;
};